package com.android.settings.audio.peq.peq;

import android.content.Context;
import android.media.AudioManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import com.android.settings.audio.peq.peq.ui.PEQActivity;
import com.android.settings.audio.peq.soundeffect.PluginDataManager;
import com.android.settings.audio.peq.util.LogPlus;
import com.android.settings.audio.peq.util.ShareprefenceTool;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class PeqAudioSettingUtils {
    private static PeqAudioSettingUtils utils;
    private AudioManager mAudioManager;
    private static final String TAG = "PeqAudioSettingUtils";
    private ExecutorService executorService;

    public static PeqAudioSettingUtils getInstance() {
        if (utils == null) {
            synchronized (PeqAudioSettingUtils.class) {
                if (utils == null) {
                    utils = new PeqAudioSettingUtils();
                }
            }
        }
        return utils;
    }

    public void enablePeq(Context context, boolean enable, boolean enablePreamp, float preamp) {
        ShareprefenceTool.getInstance().setBooleanSharedPreference(PEQActivity.PEQ_ISOPEN, enable, context);
        putStringToSettingsSystem(context, "peq_is_open", (enable ? 1 : 0) + "");
        setPeqEnableParameter(context, enable);
        setPeqPreampParameter(context, preamp);
    }

    private final java.util.Map<Integer, Band> currentAllBands = new HashMap<>();

    public void setPEQValues(final Context context, Band band, double preAmp) {
        if (executorService == null) {
            executorService = Executors.newSingleThreadExecutor();
        }

        executorService.execute(() -> {
            Band lastBand = currentAllBands.get(band.index);
            if (lastBand == null || lastBand.freq != band.freq || (lastBand.on != band.on && band.on)) setPeqItemParameter(context, band.index, "freq", (float) band.getFreq());
            if (lastBand == null || lastBand.q != band.q || (lastBand.on != band.on && band.on)) setPeqItemParameter(context, band.index, "q", (float) band.getQ());
            if (lastBand == null || lastBand.gain != band.gain || (lastBand.on != band.on && band.on)) setPeqItemParameter(context, band.index, "gain", (float) band.getGain());
            if (lastBand == null || lastBand.filterType != band.filterType || (lastBand.on != band.on && band.on)) setPeqItemParameter(context, band.index, "filter", band.filterType);
            if (lastBand == null || lastBand.on != band.on) setPeqItemParameter(context, band.index, "enable", (band.on ? 1 : 0));
            if (lastBand == null) {
                lastBand = new Band(band.index, "");
            }
            lastBand.gain = band.gain;
            lastBand.freq = band.freq;
            lastBand.q = band.q;
            lastBand.filterType = band.filterType;
            lastBand.on = band.on;
            currentAllBands.put(band.index, lastBand);
        });
    }

    public void setPEQPreamp(final Context context, double preAmp) {
        if (executorService == null) {
            executorService = Executors.newSingleThreadExecutor();
        }

        executorService.execute(() -> {
            setPeqPreampParameter(context, (float) preAmp);
        });
    }

    public void saveAllPeqData(Context context, PluginDataManager.PeqData peqData) {
        try {
            Map<String, Object> data = new HashMap<>();
            data.put("preamp", peqData.pre_amp);
            data.put("name", peqData.name);
            data.put("description", peqData.description);
            data.put("device", peqData.device);
            List<Map<String, Object>> bands = new ArrayList<>();
            data.put("bands", bands);
            for (PluginDataManager.BandItem bandItem : peqData.bands) {
                bands.add(new HashMap<String, Object>() {
                    {
                        put("freq", bandItem.freq);
                        put("q", bandItem.q);
                        put("gain", bandItem.gain);
                        put("filter", bandItem.filter);
                        put("enable", bandItem.on);
                    }
                });
            }
            JSONObject jsonObject = new JSONObject(data);
            Log.d(TAG, "saveAllPeqData: data:  " + jsonObject);
            putStringToSettingsSystem(context, "peq_data_in_setting_save", jsonObject.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private AudioManager getAudioManger(Context context) {
        if (mAudioManager == null) {
            mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        }
        return mAudioManager;
    }

    public void close() {
        if (executorService != null) {
            executorService.shutdown();
            executorService = null;
        }
    }

    public void initPeqData(Context context) {
        String peq_data_in_setting_save = Settings.System.getString(context.getContentResolver(), "peq_data_in_setting_save");
        String peq_is_open = Settings.System.getString(context.getContentResolver(), "peq_is_open");
        Log.d(TAG, "peq_data_in_setting_save: " + peq_data_in_setting_save + ",peq_is_open: " + peq_is_open);
        if ("0".equals(peq_is_open) || TextUtils.isEmpty(peq_data_in_setting_save)) return;
        setAudioParameters(context, "HIBY_DSP_SET=enable_peq|I" + peq_is_open);
        try {
            JSONObject jo = new JSONObject(peq_data_in_setting_save);
            double preAmp = jo.getDouble("preamp");
            String key = "preamp";
            setAudioParameters(context, "HIBY_DSP_SET=peq_preamp|A" + key + "|F" + preAmp);
            JSONArray jsonArray = jo.getJSONArray("bands");
            for (int i = 0, n = jsonArray.length(); i < n; ++i) {
                JSONObject jsonObject = (JSONObject) jsonArray.get(i);
                Log.d(TAG, "initpeqData: item: " + jsonObject);
                key = "freq";
                setPeqItemParameter(context, i, key, (float) jsonObject.getDouble(key));
                key = "q";
                setPeqItemParameter(context, i, key, (float) jsonObject.getDouble(key));
                key = "gain";
                setPeqItemParameter(context, i, key, (float) jsonObject.getDouble(key));
                key = "filter";
                setPeqItemParameter(context, i, key, jsonObject.getInt(key));
                key = "enable";
                setPeqItemParameter(context, i, key, jsonObject.getInt(key));
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "peq data error");
        }
    }

    public void setAudioParameters(Context context, String v) {
        LogPlus.d("###setAudioParameters v:" + v);
        getAudioManger(context).setParameters(v);
    }

    private void putStringToSettingsSystem(Context context, String name, String str) {
        try {
            Settings.System.putString(context.getContentResolver(), name, str);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public void setPeqEnableParameter(Context context, boolean enable) {
        setAudioParameters(context, "HIBY_DSP_SET=enable_peq|I" + (enable ? 1 : 0));
    }

    public void setPeqPreampParameter(Context context, float preamp) {
        String key = "preamp";
        setAudioParameters(context, "HIBY_DSP_SET=peq_preamp|A" + key + "|F" + preamp);
    }

    public void setPeqItemParameter(Context context, int bandIndex, String key, float value) {
        //HIBY_DSP_SET=peq_item0|Afreq|F2.0123
        //HIBY_DSP_SET=peq_item9|Aenable|I1
        setAudioParameters(context, "HIBY_DSP_SET=peq_item" + bandIndex + "|A" + key + "|F" + value);
    }

    public void setPeqItemParameter(Context context, int bandIndex, String key, int value) {
        setAudioParameters(context, "HIBY_DSP_SET=peq_item" + bandIndex + "|A" + key + "|I" + value);
    }
}
